#ifndef __MATRIX_INCLUDE
#define __MATRIX_INCLUDE

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

template <class T>
class Matrix {
    public:
        /** Empty constructor, not generally used. */
        Matrix();
        
        /** Default constructor.  Initializes elements to a size
            equal to the square of the matrix size.
            Parameters:
                size - the size of the matrix being represented
        */
        Matrix(int);
        
        /* Copy constructor, used to duplicate Matrix objects.  
            Used extensively by operator functions. */
        Matrix(const Matrix&);
        
        /** Default destructor.  Destroys the contained elements array. */
        ~Matrix();

        /* Assignment operator.  Copies the values of the passed matrix to
            to the newly constructed object.
            Parameter:
                matrix - the matrix to copy values from
        */
        Matrix& operator=(const Matrix&);

        /* Additive assignment operator.  Adds the values from the passed matrix,
            and assigns the value to this matrix.
            Parameter:
                matrix - the matrix to add to this matrix
        */
        Matrix& operator += (const Matrix&);
        
        /* Addition operation.  Adds two matricies together, and returns
            a new matrix that is a summation of the two.
            Parameter:
                matrix - the second matrix to be added.  The first matrix will be
                    assigned to *this.
        */
        Matrix operator + (const Matrix&) const; 

        /* Subtractive assignment operator.  Subtracts the values from the passed matrix,
            and assigns the value to this matrix.
            Parameter:
                matrix - the matrix to subtract from this matrix
        */
        Matrix& operator -= (const Matrix&);
        
        /* Subtraction operation.  Subtracts two matricies from each other, and returns
            a new matrix that is the result of the two.
            Parameter:
                matrix - the second matrix to be subtracted.  The first matrix will be
                    assigned to *this.
        */
        Matrix operator - (const Matrix&) const; 

        /* Multiplicative assignment operator.  Multiplies the passed matrix against
            this matrix.
            Parameter:
                matrix - the matrix to multiply against this matrix
        */
        Matrix& operator *= (const Matrix&);
        
        /* Multiplication operation.  Multiplies two matricies, and returns
            the product as a new matrix
            Parameter:
                matrix - the second matrix to be multiplied.  The first matrix will be
                    assigned to *this.
        */
        Matrix operator * (const Matrix&) const;

        /** Writes the matrix to the given output stream
            Parameters:
                os - the output stream to write the matrix to
                matrix - the matrix to write to the output stream
        */
        template <class Y>
        friend ostream& operator<<(ostream& os, const Matrix<Y>& matrix);

        /** Increment operator.  Adds 1 to every element in the matrix.
            Parameters:
                matrix - the matrix to increment
                unused - parameter needed to indicate this a post-fix operator
        */
        template <class Y>
        friend void operator ++ (Matrix<Y>& matrix, int);
        
        /** Decrement operator.  Subtracts 1 to every element in the matrix.
            Parameters:
                matrix - the matrix to decrement
                unused - parameter needed to indicate this a post-fix operator
        */
        template <class Y>
        friend void operator -- (Matrix<Y>& matrix, int);
        
        /** Parses a string, and creates the matrix from passed string.  The
            string is assumed to consist only of elements of the constructed type,
            and whitespace.
            Parameters:
                stream - a stream of characters and whitespace to be parsed into
                    the matrix
        */
        void parseLines(stringstream*);
        
    private:
        /** The elements of the matrix, as an array */
        T* elements;
        
        /** The last element added to the array.  When the array is completely
            initialized, last should be equal to size * size */
        T last;
        
        /** The size of the square matrix represented by this class.  This
            is the matrix size; the size of elements will be size * size 
            (as the matrix is square). */
        T size;
};

#endif